#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <cstdlib>
#include <map>
#include <set>
#include <iostream>
#include <fstream>

#include "GPSdata.hpp"
#include "GPSsplitter.hpp"
#include "GPSreceiver.hpp"

namespace ModuleData
{
  static GPSreceiver* _instance = NULL;
  GPSreceiver& instance( void )
  { 
    if (_instance == NULL) 
      _instance = new GPSreceiver();

    return *_instance;
  }
}

using namespace ModuleData;

const char DEVICE_NAME[] = "/dev/gps";
const speed_t tty_speed = B9600;

void GPSreceiver::init( void )
{
  last_actived = NULL;
  last_get = &data[0];


  for ( int i = 0; i < GPS_RECEIVER_MSG_MAX; ++i )
    {
      if ( ! msg_listeners[i].empty( ) )
	{
	  msg_listeners[i].clear( );
	}
    }
}

void GPSreceiver::add_listener( int msg_id, GPSmsg_listener _listener )
{
  if ( msg_id < 0 || msg_id >= GPS_RECEIVER_MSG_MAX )
    {				// 无效的消息id
      // give some debug print
      return;
    }

  msg_listeners[ msg_id ].insert( _listener );
}

void GPSreceiver::rmv_listener( int msg_id, GPSmsg_listener _listener )
{
  if ( msg_id < 0 || msg_id >= GPS_RECEIVER_MSG_MAX )
    {				// 无效的消息id
      // give some debug print
      return;
    }

  msg_listeners[ msg_id ].erase( _listener );
}

namespace ModuleData
{

  int device_monitor( GPSreceiver *rcv )
  {
    static char buffer[ PACKAGE_SIZE ];
    // 1 获取原始数据包，此处是从/dev/ttyS0中读取

    // 1-0 设置串口波特率
    int ret_code, tty_fd;
    /*    ret_code = open( DEVICE_NAME, O_RDWR );

      #define ERROR_1_0( error_msg )				\
      perror( error_msg );				\
      pthread_exit( reinterpret_cast<void*>( 1<<24 ) );


      termios tty_attr;
      if( ret_code == -1 )
      {
      ERROR_1_0( "open tty!" );
      }
      tty_fd = ret_code;

      ret_code = tcgetattr( tty_fd, &tty_attr );
      if( ret_code == -1 )
      {
      ERROR_1_0( "get tty attribute!" );
      }

      ret_code = cfsetispeed( &tty_attr, tty_speed );
      if( ret_code == -1 )
      {
      ERROR_1_0( "call cfsetispeed!" );
      }

      ret_code = tcsetattr( tty_fd, TCSANOW, &tty_attr );
      if( ret_code == -1 )
      {
      ERROR_1_0( "set tty attribute!" );
      }
      close( tty_fd );*/

    // 1-1 建立文件描述符
    std::ifstream dev_file( DEVICE_NAME );
    if ( !dev_file )
      {
	perror( "open device" );
	//	pthread_exit( reinterpret_cast<void*>( 1<<24|1<<16 ) );
      }

    int data_len;
    unsigned char result;
    char  *p;

    GPSdata 
      *data = rcv->data, 
      *last_get = rcv->last_get, 
      *last_actived = rcv->last_actived;

    while ( true ) {
      // 1-2 获取数据包
      strcpy( buffer, "$GPRMC,121252.000,A,108.9084,N,34.2298,E,15.15,359.95,070306,,,A*52" );//      dev_file.getline( buffer, PACKAGE_SIZE, '\n' );
      // 1-3 验证数据包

      // 1-3-1 是否长度够了
      data_len = strlen( buffer );
      if ( data_len >= PACKAGE_SIZE-1 )
	{
	  fprintf( stderr, " PACKAGE_SIZE is set too small!\n" );
	  pthread_exit( reinterpret_cast<void*>(1<<24|3<<16|1<<8) );
	}

      // 1-3-2 检验检验码
      // 1-3-2-1 找到$
      for (p = buffer; p < buffer+data_len && *p != '$'; ++p)
	{
	}
      if ( p == buffer + data_len )
	{
	  continue;
	}
      // 1-3-2-2 从$后面第一个字符开始到*之间的进行异或远算
      ++p;
      for ( result =  0; p < buffer+data_len && *p != '*'; ++p )
	{
	  result ^= *p;
	}
      if ( p == buffer + data_len )
	{
	  continue;
	}
      ++p;

      unsigned int checksum;
      sscanf( p, "%x", &checksum );
      if ( checksum != (unsigned int)result )
	{
	  // 检验码有误，丢弃
	  fprintf( stderr, " 1-3-2 :checksum wrong\n" );
	  continue;
	}


      // 2 解析包，当然是用GPSdata的类的init_data方法进行解析

      // 2-1 选择可用的位置放需要解析的数据
      if ( last_get == last_actived )
	{
	  last_get = &data[ !(last_get-data) ];
	}

      // 2-2 解析数据
      try{
	last_get->init_data( buffer, rcv->_paser );
      }
      catch( GPSdata_error& err )
	{
	  std::cerr << "errorMsg: " << err.get_error_msg() << std::endl << "Buffer: " << err.get_info() << std::endl;
	  continue; 		// 由于解析错误，就放弃执行下面的操作了
	}

      // 3 设置最近可用的data，通告回调函数

      // 3-1 回调处理
      std::set< GPSmsg_listener >::iterator iter;
      std::set< GPSmsg_listener > *listener = rcv->msg_listeners + GPS_RECEIVER_DATA_RECEIVE;
      for ( iter = listener->begin();
	    iter != listener->end();
	    ++iter )
	{
	  (*iter)();
	}

      // 3-2 处理有效的数据
      if ( last_get->is_actived() )
	{
	  last_actived = last_get;

	  listener = rcv->msg_listeners + GPS_RECEIVER_ACTIVED_DATA;
	  for ( iter = listener->begin();
		iter != listener->end();
		++iter )
	    {
	      (*iter)();
	    }
	}

    }
  }

}

void GPSreceiver::monitor( void )
{
  // 1 获取原始数据包，此处是从/dev/ttyS0中读取
  // 2 解析包，当然是用GPSdata的类的init_data方法进行解析
  // 3 设置最近可用的data
  // 以上在一个线程中进行

  pthread_t monitor;
  void *thread_retvalue;
  int err;

  // 开线程
  typedef void *(*thread_func)(void *);
  err = pthread_create( &monitor, NULL, (thread_func)device_monitor, this );
  if ( err != 0 )
    {
      perror( "create thread" );
      exit( -1 );
    }

  // 正常情况下线程是不会退出的，但是可以有其它情况，如果退出了系统就崩溃了，结束程序
  /*  err = pthread_join( monitor, &thread_retvalue );
  if ( err != 0 )
    {
      std::cerr << "step: " << (int*)thread_retvalue << std::endl;
    }

    exit( -1 );  */
}
